/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.NER;

import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import main.KBProcess.Fragment;

/**
 *
 * @author Isaac Osesina
 */
public abstract class DefaultFruit implements Fruit, Cloneable, Serializable {

	private static final long serialVersionUID = -5755068043011543984L;
	
	int myTypeCount;
    private boolean terminator;
    private boolean append;
    private Set<Object> cousinTypeList;
    private Set<Fragment> terminatingFragmentID;
    private int nonCousinTypeCount;
    private Fragment fragmentSample;

    /**
     * Seed is used to describe each context added to the Trie
     */
    public DefaultFruit() {
        init();
    }

    private void init() {
        terminator = false;
        append = false;
        nonCousinTypeCount = 0;
    }


    @Override
    public String toString()
    {
        if(this==null) {
            return null;
        }
        String s = "<; myTypeCount:" + myTypeCount + "; cousinTypeList:" + cousinTypeList + 
                   "; nonCousinTypeCount:" + nonCousinTypeCount + 
                   "; terminator:" + terminator + "; totalFreq:" + getTotalFreq()  +
                   "; ambiguous: " + isAmbiguous() + "; prunable: " + isPrunable() + "\n";
        return s;
    }

    @Override
	public boolean isAppend() {
        return append;
    }

    @Override
	public void setAppend(boolean append) {
        this.append = append;
    }
    
    @Override
	public boolean isAmbiguous() {
        if( (cousinTypeList== null || cousinTypeList.isEmpty()) && nonCousinTypeCount == 0) {
            return false;
        }
        else {
            return true;
        }
    }


    @Override
	public boolean isTerminator() {
        return terminator;
    }

    @Override
	public void setTerminator(boolean terminator) {
        this.terminator = terminator;
    }

    @Override
	public Set<Fragment> addTerminatingFragment(Fragment fragment) {
        if(fragment != null) {
            terminatingFragmentID = terminatingFragmentID == null ? new HashSet<Fragment>():terminatingFragmentID;
            terminatingFragmentID.add(fragment);
        }
        return terminatingFragmentID;
    }

    @Override
	public Set<Fragment> getTerminatingFragmentList() {
        return terminatingFragmentID;
    }

    @Override
	public int getTerminatingFragmentCount() {
        if(terminatingFragmentID == null) {
            return 0;
        }
        else {
            return terminatingFragmentID.size();
        }
    }

    @Override
	public void setTerminatingFragmentList(Set<Fragment> terminatingFragmentIDList) {
        terminatingFragmentID = new LinkedHashSet<Fragment>(terminatingFragmentIDList);
    }


    @Override
	public int getTotalFreq() {
        return myTypeCount + getCousinTypeCount() + nonCousinTypeCount;
    }

    @Override
	public int getNonCousinTypeCount() {
        return nonCousinTypeCount;
    }

    @Override
	public int setNonCousinTypeCount(int nonCousinTypeCount) {
        if(nonCousinTypeCount > getTotalFreq()) {
            this.nonCousinTypeCount = nonCousinTypeCount - myTypeCount - getCousinTypeCount();
        }
        return this.nonCousinTypeCount;
    }

    public void setValue(boolean terminator, boolean append, int FragEtype) {
        this.terminator = terminator;
        this.append = append;
    }


    public void setValue(boolean terminator, boolean append, Set<Object> cousinTypeList) {
        this.terminator = terminator;
        this.append = append;
        this.cousinTypeList = cousinTypeList;
    }


    @Override
	public int getMyTypeFreq() {
        return myTypeCount;
    }


    @Override
	public void incrementMyType(Integer idx) {
        if(idx != null)
            myTypeCount += idx;
    }

    @Override
	public Set<Object> addCousinType(Object idx) {
        cousinTypeList = cousinTypeList == null ?  new LinkedHashSet<Object>(): cousinTypeList;
        cousinTypeList.add(idx);
        return cousinTypeList;
    }

    private int getCousinTypeCount() {
        return cousinTypeList == null ? 0:cousinTypeList.size();
    }

    @Override
	public Set<Object> getCousinTypeList() {
        return cousinTypeList;
    }

    @Override
	public void setCousinTypeList(Set<Object> cousinTypeList) {
        this.cousinTypeList = cousinTypeList;
    }

    @Override
	public Fragment setFragmentSample(Fragment fragment) {
        if(fragmentSample == null) {
            fragmentSample = fragment;
        }
        return fragmentSample;
    }

    @Override
	public Fragment getFragmentSample() {
        return fragmentSample;
    }

    @Override
	public double getMyTypeProportion() {
        return myTypeCount/getTotalFreq();
    }

    @Override
	public boolean isPrunable() {
        if(this.isAmbiguous()  || (append && !this.terminator) ) {
            return false;
        }
        return true;
    }
    
    @Override
    public DefaultFruit clone()
    {
        try {
            DefaultFruit clone = (DefaultFruit) super.clone();
            return clone;
        } catch (CloneNotSupportedException ex) {
            throw new InternalError("Failed to clone");
        }
    }


}
